package com.sh.data.engine.domain.shims.postgresql.manager;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sh.data.engine.domain.shims.db.DbOptions;
import com.sh.data.engine.domain.shims.db.GenericDbManager;
import com.sh.data.engine.domain.shims.db.model.FieldInfoDomain;
import com.sh.data.engine.domain.shims.db.model.PreviewDataDomain;
import com.sh.data.engine.domain.shims.db.model.TableInfoDomain;
import com.sh.data.engine.domain.shims.db.model.TableSizeDomain;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.sql.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: mengzheng.mhc
 * @date: 2024/6/5 17:06
 */
@Slf4j
public class PostgreSqlManager extends GenericDbManager {

    public PostgreSqlManager(DbOptions options) {
        super(options);
    }

    static {
        String driverClass = "org.postgresql.Driver";
        try {
            Class.forName(driverClass);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException("Could not load db driver class: " + driverClass);
        }
    }

    /**
     * 覆写默认的connection方法,设置pg的schema
     *
     * @return
     * @throws SQLException
     */
    @Override
    protected Connection makeConnection() throws SQLException {
        Connection connection;
        String username = dbOptions.getUsername();
        String password = dbOptions.getPassword();
        String schema = dbOptions.getSchema();
        String url = dbOptions.getUrl();
        Properties connectionParams = dbOptions.getConnectionParams();

        if (schema != null && !url.contains("?currentSchema=") && url.contains("?")) {
            url += "&currentSchema=" + schema;
        } else if (schema != null && !url.contains("?currentSchema=")) {
            url += "?currentSchema=" + schema;
        }
        if (connectionParams != null && connectionParams.size() > 0) {
            log.debug(
                "User specified connection params. "
                    + "Using properties specific API for making connection.");

            Properties props = new Properties();
            if (username != null) {
                props.put("user", username);
            }

            if (password != null) {
                props.put("password", password);
            }

            props.putAll(connectionParams);
            connection = DriverManager.getConnection(url, props);
        } else {
            log.debug(
                "No connection paramenters specified. " + "Using regular API for making connection.");
            if (username == null) {
                connection = DriverManager.getConnection(url);
            } else {
                connection = DriverManager.getConnection(url, username, password);
            }
        }

        return connection;
    }

    /**
     * 敏感字段识别用
     *
     * @param schema
     * @param tableSQL
     * @return
     * @throws SQLException
     */
    @Override
    public List<TableInfoDomain> getFliterTableList(String dbName, String schema, String tableSQL)
        throws SQLException {

        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('r', 'f', 'p') AND pn.nspname = ? and pc.relname like "
                + tableSQL;

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = this.createPreparedStatement(connection, sql, schema);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public List<FieldInfoDomain> getFliterFieldList(String tableName, String fieldName)
        throws SQLException {

        String sql =
            "SELECT column_name, data_type, character_maximum_length, is_nullable,numeric_precision,numeric_scale "
                + "FROM information_schema.columns"
                + " WHERE table_schema = ?"
                + " AND table_name = ? "
                + " AND column_name like "
                + fieldName;

        List<FieldInfoDomain> fieldInfoDomains = Lists.newArrayList();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, tableName);
             ResultSet rs = pstmt.executeQuery();) {
            fieldInfoDomains = convert(rs);
        }
        return fieldInfoDomains;
    }

    @Override
    public void testConnection() throws SQLException {
        Integer timeout = dbOptions.getLoginTimeout();
        if (timeout == null) {
            timeout = 10;
        }

        String jdbcUrl = dbOptions.getUrl();
        // loginTimeout参数对pg不生效
        // 见 https://segmentfault.com/a/1190000008310730
        if (!StringUtils.contains(jdbcUrl, "socketTimeout=")
            && !StringUtils.contains(jdbcUrl, "connectTimeout=")) {

            // 如果jdbc中有?或者&，说明已经有参数了，这时直接append就行
            if (StringUtils.contains(jdbcUrl, "?") || StringUtils.contains(jdbcUrl, "&")) {
                jdbcUrl = jdbcUrl + "&socketTimeout=" + timeout + "&connectTimeout=" + timeout;
            } else {
                // jdbc中没有参数，socketTimeout和connectTimeout放到?之后
                jdbcUrl = jdbcUrl + "?socketTimeout=" + timeout + "&connectTimeout=" + timeout;
            }
        }

        try (Connection conn =
                 DriverManager.getConnection(jdbcUrl, dbOptions.getUsername(), dbOptions.getPassword())) {
        } catch (SQLException e) {
            throw new SQLException(toReadableMsg(e), e);
        }
    }

    @Override
    public String getQueryVersionSql() {
        return "SHOW server_version";
    }

    @Override
    public PreviewDataDomain previewData(String schema, String tableName) throws SQLException {
        return super.previewData(escapeTableName(schema) + "." + escapeTableName(tableName));
    }

    @Override
    public String getQuerySchemaListSql() {
        String sql =
            "select nspname from pg_namespace where nspname not like 'pg_%' and nspname <> 'information_schema'";
        return sql;
    }

    @Override
    public boolean alterFieldDesc(
        String dbName, String tableName, String fieldName, String fieldDes, boolean isPartition)
        throws SQLException {

        String sql =
            String.format("COMMENT ON COLUMN %s.%s.%s IS '%s'", dbName, tableName, fieldName, fieldDes);
        doAlertFiledDesc(sql);
        return true;
    }

    @Override
    public List<TableInfoDomain> getTableList(String dbName) throws SQLException {

        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('r', 'f', 'p') AND pn.nspname NOT IN ( 'pg_catalog', 'information_schema')";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = this.createPreparedStatement(connection, sql);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public List<TableInfoDomain> getTableList(String dbName, String schema) throws SQLException {
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('r', 'f', 'p') AND pn.nspname = ?";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = this.createPreparedStatement(connection, sql, schema);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    private static TableInfoDomain getTableDomain(String dbName, ResultSet rs) throws SQLException {
        ResultSetMetaData meta = rs.getMetaData();
        Set<String> set = new HashSet<>();
        for (int index = 1; index <= meta.getColumnCount(); index++) {
            set.add(meta.getColumnLabel(index));
        }
        TableInfoDomain entity = new TableInfoDomain();
        entity.setDbName(dbName);

        if (set.contains("nspname")) {
            String nspname = rs.getString("nspname");
            entity.setSchema(nspname);
        }

        if (set.contains("relname")) {
            String tblName = rs.getString("relname");
            entity.setTableName(tblName);
        }

        if (set.contains("oid")) {
            Long tblId = rs.getLong("oid");
            entity.setTblId(tblId);
        }

        if (set.contains("relkind")) {
            String relkind = rs.getString("relkind");
            TableInfoDomain.TblType tblType = null;
            switch (relkind) {
                case "r":
                    tblType = TableInfoDomain.TblType.MANAGED_TABLE;
                    break;
                case "p": // 分区表
                    tblType = TableInfoDomain.TblType.MANAGED_TABLE;
                    entity.setPartitionTable(true);
                    break;
                case "f":
                    tblType = TableInfoDomain.TblType.EXTERNAL_TABLE;
                    break;
                case "v":
                case "m":
                    tblType = TableInfoDomain.TblType.VIEW;
                    break;
            }
            entity.setTblType(tblType);
        }

        return entity;
    }

    private void batchSetTableProperty(List<TableInfoDomain> list, Connection conn)
        throws SQLException {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        String idStr =
            list.stream()
                .map(e -> e.getTblId())
                .filter(Objects::nonNull)
                .distinct()
                .map(e -> e.toString())
                .collect(Collectors.joining(","));

        // 查询表属性
        String sql =
            "select objoid,description from pg_description where objoid in ("
                + idStr
                + ") and objsubid = 0";

        Map<Long, String> tablePropertyMap = new LinkedHashMap<>();

        try (PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                Long tblId = rs.getLong("objoid");
                String comment = rs.getString("description");

                if (StringUtils.isBlank(comment)) {
                    continue;
                }
                tablePropertyMap.put(tblId, comment);
            }
        }

        list.forEach(
            table -> {
                final String comment = tablePropertyMap.getOrDefault(table.getTblId(), null);
                table.setTableComment(comment);
            });
    }

    @Override
    public List<TableInfoDomain> getViewList(String dbName) throws SQLException {
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('v','m') AND pn.nspname NOT IN ( 'pg_catalog', 'information_schema')";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = connection.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public List<TableInfoDomain> getViewList(String dbName, String schema) throws SQLException {
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('v','m') AND pn.nspname = ?";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, schema);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public List<TableInfoDomain> getTableAndViewList(String dbName) throws SQLException {
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('r', 'f', 'p','v','m') AND pn.nspname NOT IN ( 'pg_catalog', 'information_schema')";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = connection.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public List<TableInfoDomain> getTableAndViewList(String dbName, String schema)
        throws SQLException {
        if (StringUtils.isBlank(schema)) {
            return getTableAndViewList(dbName);
        }
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pc.relkind IN ('r', 'f', 'p','v','m') AND pn.nspname = ?";

        List<TableInfoDomain> list = new LinkedList<>();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, schema);
             ResultSet rs = pstmt.executeQuery()) {
            while (rs != null && rs.next()) {
                final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                list.add(tableDomain);
            }

            batchSetTableProperty(list, connection);
        }
        return list;
    }

    @Override
    public TableInfoDomain getTableInfoByTableName(String dbName, String tableName)
        throws SQLException {

        if (StringUtils.isNotBlank(dbOptions.getSchema())) {
            return getTableInfoByTableName(dbName, dbOptions.getSchema(), tableName);
        }

        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pn.nspname NOT IN ('pg_catalog', 'information_schema') AND pc.relname = ?";

        try (Connection connection = getConnection()) {
            List<TableInfoDomain> list = new LinkedList<>();
            try (PreparedStatement pstmt = createPreparedStatement(connection, sql, tableName);
                 ResultSet rs = pstmt.executeQuery()) {
                while (rs != null && rs.next()) {
                    final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                    list.add(tableDomain);
                }

                batchSetTableProperty(list, connection);
            }

            return list.isEmpty() ? null : list.get(0);
        }
    }

    @Override
    public TableInfoDomain getTableInfoByTableName(String dbName, String schema, String tableName)
        throws SQLException {
        String sql =
            "select pc.oid,pc.relname,pc.relkind,pn.nspname from pg_class pc "
                + "left join pg_namespace pn on pc.relnamespace = pn.oid "
                + "where pn.nspname NOT IN ('pg_catalog', 'information_schema') AND pc.relname = ? AND pn.nspname = ?";

        try (Connection connection = getConnection()) {
            List<TableInfoDomain> list = new LinkedList<>();
            try (PreparedStatement pstmt = createPreparedStatement(connection, sql, tableName, schema);
                 ResultSet rs = pstmt.executeQuery()) {
                while (rs != null && rs.next()) {
                    final TableInfoDomain tableDomain = getTableDomain(dbName, rs);
                    list.add(tableDomain);
                }

                batchSetTableProperty(list, connection);
            }

            return list.isEmpty() ? null : list.get(0);
        }
    }

    /**
     * 获取字段列表 如果不添加namespace的where条件会查出其他schema下的同名表字段
     *
     * @param dbName
     * @param tableName
     * @return
     */
    @Override
    public List<FieldInfoDomain> getFieldList(String dbName, String tableName) throws SQLException {
        if (StringUtils.isNotBlank(dbOptions.getSchema())) {
            return getFieldList(dbName, dbOptions.getSchema(), tableName);
        }

        String sql =
            "SELECT cols.column_name, cols.data_type, cols.is_nullable,"
                + "cols.character_maximum_length,"
                + "cols.numeric_precision,"
                + "cols.numeric_scale,"
                + "pg_catalog.col_description(c.oid, cols.ordinal_position::int) as comment "
                + "FROM pg_catalog.pg_class c, information_schema.columns cols "
                + "WHERE cols.table_name = c.relname AND cols.table_name = ?";

        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, tableName);
             ResultSet rs = pstmt.executeQuery()) {
            return convert(rs);
        }
    }

    @Override
    public List<FieldInfoDomain> getFieldList(String dbName, String schema, String tableName)
        throws SQLException {

        //    String sql =
        //        "SELECT cols.column_name, cols.data_type, cols.is_nullable,"
        //            + "cols.character_maximum_length,"
        //            + "cols.numeric_precision,"
        //            + "cols.numeric_scale,"
        //            + "pg_catalog.col_description(c.oid, cols.ordinal_position::int) as comment "
        //            + "FROM pg_catalog.pg_class c, information_schema.columns cols "
        //            + "WHERE cols.table_name = c.relname AND c.relnamespace = ( select
        // pg_namespace.OID from pg_namespace where nspname = ? )"
        //            + "AND cols.table_schema = ? AND cols.table_name = ?";

        String sql =
            "SELECT column_name, data_type, character_maximum_length, is_nullable,numeric_precision,numeric_scale "
                + "FROM information_schema.columns"
                + " WHERE table_schema = ?"
                + "  AND table_name = ?";

        String getComment =
            "SELECT a.attname AS column_name, d.description AS column_comment\n"
                + "FROM pg_attribute a\n"
                + "LEFT JOIN pg_description d ON a.attrelid = d.objoid AND a.attnum = d.objsubid\n"
                + "WHERE a.attrelid = '\""
                + schema
                + "\".\""
                + tableName
                + "\"'::regclass \n"
                + "  AND a.attnum > 0 \n"
                + "  AND NOT a.attisdropped;";

        String getPK =
            "SELECT a.attname AS column_name "
                + "FROM pg_constraint c "
                + "JOIN pg_attribute a ON c.conrelid = a.attrelid AND a.attnum = ANY(c.conkey) "
                + "WHERE c.conrelid = '\""
                + schema
                + "\".\""
                + tableName
                + "\"'::regclass"
                + "  AND c.contype = 'p'"
                + " ORDER BY a.attnum;";

        List<FieldInfoDomain> fieldInfoDomains = Lists.newArrayList();
        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, schema, tableName);
             ResultSet rs = pstmt.executeQuery();
             PreparedStatement comment = createPreparedStatement(connection, getComment);
             ResultSet commentRs = comment.executeQuery();
             PreparedStatement pk = createPreparedStatement(connection, getPK);
             ResultSet pkRs = pk.executeQuery();) {
            fieldInfoDomains = convert(rs);
            fieldInfoDomains = convertComment(commentRs, fieldInfoDomains);
            fieldInfoDomains = convertPk(pkRs, fieldInfoDomains);
        }
        return fieldInfoDomains;
    }

    @Override
    public List<FieldInfoDomain> getFieldList(
        String dbName, String schema, String tableName, Connection connection) throws SQLException {

        String sql =
            "SELECT column_name, data_type, character_maximum_length, is_nullable,numeric_precision,numeric_scale "
                + "FROM information_schema.columns"
                + " WHERE table_schema = ?"
                + "  AND table_name = ?";

        String getComment =
            "SELECT a.attname AS column_name, d.description AS column_comment\n"
                + "FROM pg_attribute a\n"
                + "LEFT JOIN pg_description d ON a.attrelid = d.objoid AND a.attnum = d.objsubid\n"
                + "WHERE a.attrelid = '\""
                + schema
                + "\".\""
                + tableName
                + "\"'::regclass \n"
                + "  AND a.attnum > 0 \n"
                + "  AND NOT a.attisdropped;";

        String getPK =
            "SELECT a.attname AS column_name "
                + "FROM pg_constraint c "
                + "JOIN pg_attribute a ON c.conrelid = a.attrelid AND a.attnum = ANY(c.conkey) "
                + "WHERE c.conrelid = '\""
                + schema
                + "\".\""
                + tableName
                + "\"'::regclass"
                + "  AND c.contype = 'p'"
                + " ORDER BY a.attnum;";

        List<FieldInfoDomain> fieldInfoDomains = Lists.newArrayList();
        try (PreparedStatement pstmt = createPreparedStatement(connection, sql, schema, tableName);
             ResultSet rs = pstmt.executeQuery();
             PreparedStatement comment = createPreparedStatement(connection, getComment);
             ResultSet commentRs = comment.executeQuery();
             PreparedStatement pk = createPreparedStatement(connection, getPK);
             ResultSet pkRs = pk.executeQuery();) {
            fieldInfoDomains = convert(rs);
            fieldInfoDomains = convertComment(commentRs, fieldInfoDomains);
            fieldInfoDomains = convertPk(pkRs, fieldInfoDomains);
        }
        return fieldInfoDomains;
    }

    @SneakyThrows
    private List<FieldInfoDomain> convertPk(ResultSet rsPk, List<FieldInfoDomain> fieldInfoDomains) {
        Set<String> pkSet = Sets.newHashSet();
        while (rsPk.next()) {
            String columnName = rsPk.getString(1);
            pkSet.add(columnName);
        }

        for (FieldInfoDomain fieldInfoDomain : fieldInfoDomains) {
            String fieldName = fieldInfoDomain.getFieldName();
            if (pkSet.contains(fieldName)) {
                fieldInfoDomain.setPk(true);
            }
        }
        return fieldInfoDomains;
    }

    private List<FieldInfoDomain> convertComment(ResultSet rs, List<FieldInfoDomain> fieldInfoDomains)
        throws SQLException {

        Map<String, String> commentMap = Maps.newHashMap();
        while (rs.next()) {
            String columnName = rs.getString(1);
            String columnComment = rs.getString(2);
            commentMap.put(columnName, columnComment);
        }

        for (FieldInfoDomain fieldInfoDomain : fieldInfoDomains) {
            String fieldName = fieldInfoDomain.getFieldName();
            String comment = commentMap.get(fieldName);
            fieldInfoDomain.setComment(comment);
        }

        return fieldInfoDomains;
    }

    private List<FieldInfoDomain> convert(ResultSet rs) throws SQLException {
        ArrayList<String> charTypes = Lists.newArrayList("character varying", "character");

        List<FieldInfoDomain> list = new LinkedList<>();

        ResultSetMetaData metaData = rs.getMetaData();

        while (rs.next()) {
            FieldInfoDomain fieldInfoDomain = new FieldInfoDomain();

            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                String fieldKey = metaData.getColumnName(i);
                String fieldValue = rs.getString(i);
                if ("column_name".equals(fieldKey)) {
                    fieldInfoDomain.setFieldName(fieldValue);
                } else if ("data_type".equals(fieldKey)) {
                    fieldInfoDomain.setFieldType(fieldValue);
                } else if ("is_nullable".equals(fieldKey)) {
                    fieldInfoDomain.setNullable("YES".equals(fieldValue) ? Boolean.TRUE : Boolean.FALSE);
                } else if ("character_maximum_length".equals(fieldKey)) {
                    if (charTypes.contains(fieldInfoDomain.getFieldType())) {
                        if (StringUtils.isEmpty(fieldValue)) {
                            fieldValue = "500";
                        }
                        if (StringUtils.isNotBlank(fieldValue)) {
                            fieldInfoDomain.setColumnSize(Integer.valueOf(fieldValue));
                        }
                        fieldInfoDomain.setFieldType(fieldInfoDomain.getFieldType() + "(" + fieldValue + ")");
                    }
                } else if ("numeric_precision".equals(fieldKey)) {
                    if (Objects.equals("numeric", fieldInfoDomain.getFieldType())) {
                        if (StringUtils.isEmpty(fieldValue)) {
                            fieldValue = "1";
                        }
                        fieldInfoDomain.setColumnSize(Integer.valueOf(fieldValue));
                        fieldInfoDomain.setFieldType(fieldInfoDomain.getFieldType() + "(" + fieldValue);
                    }
                } else if ("numeric_scale".equals(fieldKey)) {
                    if (null != fieldInfoDomain.getFieldType()
                        && fieldInfoDomain.getFieldType().startsWith("numeric")) {
                        if (StringUtils.isEmpty(fieldValue)) {
                            fieldValue = "1";
                        }
                        fieldInfoDomain.setDecimalDigits(Integer.valueOf(fieldValue));
                        fieldInfoDomain.setFieldType(fieldInfoDomain.getFieldType() + "," + fieldValue + ")");
                    }
                }
            }
            list.add(fieldInfoDomain);
        }

        return list;
    }

    @Override
    public List<TableSizeDomain> getTableSizeList(String dbName, String schema) throws SQLException {
        String sql =
            "SELECT table_schema, TABLE_NAME, "
                + "pg_total_relation_size ( '\"' || table_schema || '\".\"' || TABLE_NAME || '\"' ) AS SIZE "
                + "FROM information_schema.tables "
                + "WHERE table_catalog = ? and table_schema = ? ";

        List<TableSizeDomain> list = new ArrayList<>();

        try (Connection connection = getConnection();
             PreparedStatement pstmt = createPreparedStatement(connection, sql, dbName, schema);
             ResultSet rs = pstmt.executeQuery()) {

            while (rs.next()) {
                TableSizeDomain domain = new TableSizeDomain();
                final String tableName = rs.getString("table_name");
                final long size = rs.getLong("size");
                final String tableSchema = rs.getString("table_schema");
                domain.setTableSize(size);
                domain.setTableName(tableName);
                domain.setSchema(tableSchema);
                list.add(domain);
            }
            return list;
        }
    }

    public static void main(String[] args) throws SQLException {
        DbOptions dbOptions = new DbOptions();
        dbOptions.setUrl("jdbc:postgresql://10.88.36.186:5432/postgres");
        dbOptions.setUsername("postgres");
        dbOptions.setPassword("123456");
        dbOptions.setSchema("hufu");
        var manager = new PostgreSqlManager(dbOptions);

        Connection connection = manager.getConnection();
        List<FieldInfoDomain> fieldList1 = manager.getFieldList("postgres", "public", "ods_fsdfsa");
        System.out.println(fieldList1.toString());

        //    String sql =
        //        "select \"content\" from (select distinct \"content\" from hufu.biz_data_index where
        // to_tsvector('jiebaqry',content) @@ to_tsquery('jiebaqry','子级') and project_id =
        // '620c74a0a3e82365a101e5bc' limit 1000) t ORDER BY ts_rank(to_tsvector('jiebaqry',\"content\")
        // ,to_tsquery('jiebaqry','子级'),8) desc";

        String sql =
            "select * from to_tsquery('jiebacfg', '是拖拉机学院手扶拖拉机专业的。不用多久，我就会升职加薪，当上CEO，走上人生巅峰。')";

        List<FieldInfoDomain> fieldList = manager.getFieldList("postgres", "tests", "ods_lx_test");
        PreparedStatement preparedStatement = connection.prepareStatement(sql);

        ResultSet resultSet = preparedStatement.executeQuery();

        while (resultSet.next()) {
            System.out.println(resultSet.getString(1));
        }

        //    final List<TableInfoDomain> tableInfoDomains = manager.getTableList("postgres");
        //
        //    for (TableInfoDomain tableInfoDomain : tableInfoDomains) {
        //      System.out.println(tableInfoDomain);
        //    }
        //    final PreviewDataDomain previewDataDomain = manager.previewData("goods");
        //    System.out.println(previewDataDomain.toString());
        //
        //    final TableInfoDomain tableInfoDomain = manager.getTableInfoByTableName("postgres",
        // "goods");
        //    System.out.println(tableInfoDomain);
        //
        //    final List<FieldInfoDomain> fieldList = manager.getFieldList("postgres", "test");
        //    System.out.println(fieldList);

    }
}
